// Copyright (c) 2012 Rene Bolldorf <rb@radix.io>
// Use of this source is governed by the GNU General Public License version 3,
// the license can be found in the LICENSE file.

var doa = function (userId, dragonHeart, realm) {
  this._reqDelegate = new this.requestDelegate(realm, userId, dragonHeart);
  this._jobQueue = [];
  this._cities = null;

  this.console = document.querySelector('#console');
  this.cli = document.querySelector('#cli');
  this.cmds = { 'clear' : [ this.clear, 'Clear the console'],
                'player' : [ this.player, 'Show information about the player' ],
                'generals' : [ this.generals, 'List your generals.' ],
                'jobs' : [ this.jobs, 'List all jobs in the game queue.' ],
                'attack' : [ this.attack, 'Send attack. e.g. attack 123/456 ' +
                                          'GreatDragon:1,Longbowman:10000 ' +
                                          '400 <-(optional, repeat each N seconds, min. 30)' ],
                'autocollect' : [ this.autoCollect, 'Auto collect resources from your outposts' ],
                'autoupgrade' : [ this.autoUpgrade, 'Auto upgrade buildings if possible' ],
                'displayjobs' : [ this.displayJobs, 'Display all repeating jobs' ],
                'removejob' : [ this.removeJob, 'Remove a repeating job. Usage: removeJob job_id' ]
  };
  this.cliDatalist = document.querySelector('#commands');
  for (k in this.cmds) {
    var opt = document.createElement('option');
    opt.value = k;
    opt.innerText = this.cmds[k][1];
    this.cliDatalist.appendChild(opt);
  }

  this.cliListener(this.cli);

  document.querySelector('#inner').style.display = 'block';
  this.write('Welcome !');
  // for debug purposes
  window.doa = this;
};

doa.prototype.write = function (msg) {
  if (msg == null)
    this.console.innerText = '';
  else
    this.console.innerText = msg + '\n' +
      this.console.innerText;
};

doa.prototype.clear = function () {
  this.write(null);
};

doa.prototype.cliListener = function (elem) {
  var self = this;

  elem.addEventListener('change', function () {
    var args = this.value.split(' ');
    var cmd = args.shift();

    this.value = '';
    if (cmd in self.cmds) {
      self.write('Command executed. That may take a moment');
      self.cmds[cmd][0].apply(self, args);
    } else
      self.write('unknown command: ' + cmd);

  }, false);
};

doa.prototype.addJob = function (job) {
  if (job.repeat && job.repeat >= 30) {
    job.id = window.setInterval(function (scope) {
        job.func.apply(scope, job.args);
    }, job.repeat * 1000, job.scope);

    this._jobQueue.push(job);
    switch (job.type) {
      case 'auto-collect':
        this.write(job.type + 'ing ' + job.name);
        break;
      default:
        this.write(job.type + ' will repeated each ' +
                   job.repeat + ' seconds');
    }
  } else {
    this.write('One time ' + job.type);
  }

  job.func.apply(job.scope, job.args);
};

doa.prototype.removeJob = function (job_id) {
  if (!job_id) {
    this.write('Please provide a job id, type "displayjobs" to display all jobs');
    return;
  }
  var a = this._jobQueue;

  for (var i=0; i < a.length; i++) {
    if (a[i].id == job_id) {
      a.splice(i, 1);
      window.clearInterval(job_id);
      this.write('Successfully removed job ' + job_id);
      return;
    }
  }
  this.write('Could not remove job, maybe it does not exist anymore?');
};

doa.prototype.getJobs = function (type) {
  var ret = [];

  this._jobQueue.forEach(function (job) {
    if (job.type == type)
      ret.push(job);
  });
  return ret;
};

doa.prototype.displayJobs = function () {
  var str = '';

  this._jobQueue.forEach(function (job) {
    str += '\nid: ' + job.id + ', '
          + job.name + ' '
          + job.type + ' each '
          + job.repeat + ' seconds';

    switch(job.type) {
      case 'attack':
        str += ' ' + job.x + '/' + job.y + ' ' + job.troops;
        break;
    }
  });

  if (str.length == 0)
    str = 'No repeating jobs found'

  this.write(str);
};

doa.prototype.getCapitalId = function (callback) {
  var self = this;

  this._reqDelegate.player(false, function (obj, err) {
    if (!err)
      callback(obj['cities']['capital']['id']);
    else
      self.write('a error occured: ' + err);
  });
};

// TODO: display more information
doa.prototype.player = function () {
  var self = this;

  this._reqDelegate.player(false, function (obj, err) {
    if (!err) {
      var str = 'Name: ' + obj['name'] + '\n' +
                'Race: ' + obj['race'] + '\n' +
                'Level: ' + obj['level'] + '\n' +
                'Power: ' + obj['might'] + '\n' +
                'Maximal Wildernesses: ' + obj['max_wildernesses'];
      var cities = obj['cities'];
      self._cities = cities;
      for (city in cities) {
        str += '\n' + cities[city]['name'] + ':\n' +
               '     level ' + cities[city]['level'] +
               ' ' + cities[city]['x'] + '/' + cities[city]['y'];
      }
      self.write(str);
    } else
      self.write('a error is occured: ' + err);
  });
};

doa.prototype.generals = function () {
  var self = this;

  this.getCapitalId(function (capital_id) {
    self._reqDelegate.generals(false, capital_id, function (obj, err) {
      if (!err) {
        var str = '';
        obj['generals'].forEach(function (general) {
          str += '\nName: ' + general['name'] +
                 '\n     Rank: ' + general['rank'] +
                 '\n     Victories: ' + general['victories'];
        });
        self.write(str);
      } else
        self.write('a error is occured: ' + err);
    });
  });
};

doa.prototype.jobs = function () {
  var self = this;

  this._reqDelegate.jobs(false, function (obj, err) {
    if (!err) {
      var result = obj['result']['result'];
      var str = '';
      for (city in result) {
        str += city + ':\n';
        result[city].forEach(function (job) {
          var type = job['queue'];
          var complete_in = ' complete in ' + util.untilTo(job['run_at']);

          str += '     ' + type;
          switch(type) {
            case 'research':
              str += ' ' + job['research_type'] +
                     ' level ' + job['level'] +
                     complete_in + '\n';
              break;
            case 'building':
              str += ' ' + job['city_building_type'] +
                     ' level ' + job['level'] +
                     complete_in + '\n';
              break;
            case 'units':
              str += ' ' + job['quantity'] + ' x ' + job['unit_type'] +
                     complete_in + '\n';
              break;
            case 'march':
              str += ' unimplented ' + complete_in + '\n';
              break;
            case 'dragon':
              str += ' healing' + complete_in + '\n';
              break;
            case 'trade':
              str += ' unimplented\n';
              break;
          }
        });
      }
      self.write(str);
    } else
      self.write('a error is occured: ' + err);
  });
};

doa.prototype.attack = function (coords, troops, repeat) {
  if (!coords || !troops) {
    this.write('arguments: coords troops repeat');
    return;
  }

  var self = this;
  var c = coords.split('/');
  var x = c[0];
  var y = c[1];
  var my_troops = {};

  this.getCapitalId(function (capital_id) {
    self._reqDelegate.city(true, capital_id, function (obj, err) {
      if (!err) {
        var marches = {};
        var avail_general = null;
        obj['city']['marches'].forEach(function (march) {
          marches[march['general_id']] = true;
        });

        var generals = obj['city']['generals'];

        for (var i=0; i < generals.length; i++) {
          var id = generals[i]['id'];
          if (marches[id] != true) {
            avail_general = [ generals[i]['name'], id ];
            break;
          }
        }

        if (!avail_general) {
          self.write('No free general available');
          return;
        }

        var _troops = troops.split(',');
        _troops.forEach(function (i) {
          var troop = i.split(':'); 
          my_troops[troop[0]] = troop[1];
        });

        var callback = function (obj, err) {
          if (err)
            self.write('could not send attack to ' + coords + ', reason: ' + err);
        };

          var job = new window.job.march();
          job.scope = self._reqDelegate;
          job.func = self._reqDelegate.attack;
          job.args = [x, y, avail_general[1], my_troops, capital_id, callback];
          job.type = 'attack';
          job.x = x;
          job.y = y;
          job.name = avail_general[0];
          job.troops = troops;
          job.repeat = repeat;
          self.addJob(job);

      } else
        self.write('there was a error: ' + err);
    });
  });
};

doa.prototype.autoCollect = function () {
  var self = this;

  if (!this._cities) {
    this._reqDelegate.player(false, function (obj, err) {
      if (!err) {
        self._cities = obj['cities'];
        self.autoCollect();
      } else
        self.write('a error is occured: ' + err);
    });
    return;
  }

  var collect = false;

  for (city in this._cities) {
    if (city != 'capital' && city != 'spectral') {
      collect = true;
      var id = this._cities[city]['id'];
      var name = this._cities[city]['name'];
      var callback = function (err) {
        if (err)
          self.write('Could not collect resources from ' + name +
                     ' , reason: ' + err);
      };
      var job = new window.job.collect();

      job.scope = self._reqDelegate;
      job.func = self._reqDelegate.collect;
      job.args = [id, callback];
      job.name = name;
      job.repeat = 600;
      this.addJob(job);
    }
  }

  if (!collect)
    this.write('You have no cities to collect resources from');
};

doa.prototype.autoUpgrade = function() {
  if (this.getJobs('auto-upgrade').length > 0) {
    this.write('You already have auto-upgrade enabled, remove that job first');
    return;
  }

  var self = this;

  if (!this._cities) {
    this._reqDelegate.player(false, function (obj, err) {
      if (!err) {
        self._cities = obj['cities'];
        self.autoUpgrade();
      } else
        self.write('a error is occured: ' + err);
    });
  } else {

    var buildings = {};

    for (city in this._cities) {
      var city_id = this._cities[city]['id'];
      buildings[city_id] = [];

      this._reqDelegate.city(false, city_id, function (obj, err) {
        if (!err) {
          obj['city']['buildings'].forEach(function (building) {
            buildings[building['city_id']].push(building);
          });
        }
      });
    }

    var doUpgrade = function (buildings) {
      for (city in buildings) {
        if (buildings[city].length > 0) {
          // TODO: find out if we really can upgrade,
          // we just fail silently now
          var building = buildings[city].shift();
          // don't upgrade buildings level 9 and higher
          // (completion grants etc.)
          var level = building['level'];
          if (level < 9) {
            // seperate the requests a bit
            window.setTimeout(function (scope, city_id, building_id) {
              scope._reqDelegate.upgrade(city_id, building_id,
               function (err) {});
              }, Math.floor((Math.random()*30)+1) * 1000,
                this, building['city_id'], building['id']
            );
            if (level != 8)
              buildings[city].push(building);
          }
        }
      }
    };

    var job = new window.job.upgrade();
    job.scope = this;
    job.func = doUpgrade;
    job.args = [ buildings ];
    job.name = 'buildings';
    job.repeat = 180;
    this.addJob(job);
  }
};

window.onload = function () {
  var form = document.querySelector('#userinfo');
  var datalist_user = form.querySelector('#userlist');
  var datalist_heart = form.querySelector('#heartlist');
  var datalist_realm = form.querySelector('#realmlist');
  var obj = storage.loadUserInfo();
  var dlist = [ form.querySelector('#userlist'),
                form.querySelector('#heartlist'),
                form.querySelector('#realmlist')
  ];

  for(var i=0; i < obj.length; i++) {
    for(var _i=0; _i < obj[i].length; _i++) {
      var e = document.createElement('option');
      e.value = obj[i][_i];
      dlist[i].appendChild(e);
    }
  }
  var onEnter = function (e) {
    if (e.keyCode == 13) {
      var user = e.target.form[0].value;
      var dragonheart = e.target.form[1].value;
      var realm = e.target.form[2].value;

      e.target.form.parentElement.style.display = 'none';
      storage.saveUserInfo([ user, dragonheart, realm ]);
      new doa(user, dragonheart, realm);
      form.removeEventListener('keydown', onEnter, false);
    }
  };
  form.addEventListener('keydown', onEnter, false);
};
